package top.zhangjianyong.blog.config.mybatisplus;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import java.time.LocalDateTime;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import top.zhangjianyong.blog.cache.UserCache;
import top.zhangjianyong.blog.config.blog.BlogConfig;

/**
 * mybatis-plus配置类
 *
 * @author zhangjianyong
 * @since 2024/7/19 上午10:09
 */
@Slf4j
@Configuration
public class MyBatisPlusConfig {

  private final BlogConfig blogConfig;

  public MyBatisPlusConfig(BlogConfig blogConfig) {
    this.blogConfig = blogConfig;
  }

  /** 添加分页插件 */
  @Bean
  public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(
        new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
    // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
    return interceptor;
  }

  /*主键生成器*/
  @Bean
  public IdentifierGenerator identifierGenerator() {
    return new IdentifierGenerator() {
      private final IdWorker idWorker =
          IdWorker.create(
              blogConfig.getIdSequence().getWorkerId(),
              blogConfig.getIdSequence().getDataCenterId());

      @Override
      public Number nextId(Object entity) {
        return idWorker.nextId();
      }
    };
  }

  @Bean
  public MetaObjectHandler metaObjectHandler() {
    return new MyMetaObjectHandler();
  }

  /** 静态内部类实现 MetaObjectHandler，避免匿名内部类持有外部类引用，提升性能 */
  private static class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
      log.info("start insert fill ....");
      this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
      this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
      this.setFieldValByName("isDel", 0, metaObject);

      Optional.ofNullable(UserCache.user())
          .ifPresent(
              user -> {
                this.setFieldValByName("createUser", user.getId(), metaObject);
                this.setFieldValByName("updateUser", user.getId(), metaObject);
              });
    }

    @Override
    public void updateFill(MetaObject metaObject) {
      log.info("start update fill ....");
      this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
      Optional.ofNullable(UserCache.user())
          .ifPresent(user -> this.setFieldValByName("updateUser", user.getId(), metaObject));
    }
  }
}
